home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / amigadev.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  16KB  |  699 lines

  1. /*
  2.  *  Copyright (C) 1987
  3.  *  Louis A. Mamakos  WA3YMH
  4.  *  All rights reserved.
  5.  *
  6.  *  This code may not be redistributed, sold, included on any collection of
  7.  *  software which is sold.  Use of this software is restricted to inclusion
  8.  *  in the KA9Q TCP/IP software package for use on a Commodore-Amiga system.
  9.  *  Commercial use is prohibited.  Only educational and Amateur Packet Radio
  10.  *  use is allowed.
  11.  */
  12.  
  13. #ifdef    AMIGADEVDRV
  14. /*
  15.  *  This module is the meat of the Amiga 'internet.device' device driver.  There
  16.  *  are assembly language stubs in devstub.asm that call this module when user
  17.  *  program access the device driver.  Remember: the tasks running this code are
  18.  *  not our own!
  19.  */
  20.  
  21. #include <stdio.h>
  22.  
  23. /* Amiga system definitions */
  24.  
  25. #include <exec/types.h>
  26. #include <exec/nodes.h>
  27. #include <exec/lists.h>
  28. #include <exec/tasks.h>
  29. #include <exec/ports.h>
  30. #include <exec/libraries.h>
  31. #include <exec/io.h>
  32. #include <exec/devices.h>
  33. #include <exec/errors.h>
  34.  
  35.  
  36. /* get definitions of KA9Q TCP/IP protocol stuff... */
  37.  
  38. #include "machdep.h"
  39. #include "timer.h"
  40. #include "mbuf.h"
  41. #include "netuser.h"
  42. #include "internet.h"
  43. #include "icmp.h"
  44. #include "ip.h"
  45. #include "tcp.h"
  46. #include "trace.h"
  47. #include "session.h"
  48. /* device driver specific definitions */
  49. #define ListEmpty(x)    (! ((x)->lh_Head->ln_Succ))
  50.  
  51. #include "inetdev.h"
  52. #ifdef TRACE 
  53. #define tracedev(x) \
  54.     if (trace & TRACE_DEVICE) printf(x)
  55.  
  56. #define tracedev2(x,y) \
  57.     if (trace & TRACE_DEVICE) printf(x,y)
  58.  
  59. #define tracedev3(x,y,z) \
  60.     if (trace & TRACE_DEVICE) printf(x,y,z)
  61.  
  62. #define tracedev4(x,y,z,zz) \
  63.     if (trace & TRACE_DEVICE) printf(x,y,z,zz)
  64. #endif
  65. char *malloc();
  66.  
  67. extern void DSClose(), DSBeginIO(), DSAbortIO();
  68. extern struct InternetBase *DSOpen();
  69. extern long DSExpunge();
  70.  
  71. void indev_tcp_r_upcall(), indev_tcp_t_upcall(), indev_s_upcall();
  72. struct SignalSemaphore INLock;
  73. struct Library *MakeLibrary();
  74.  
  75. /* for open requests */
  76. int nopens; /* from iface */
  77. struct IOINETReq *iob = NULL;
  78. int unit_spec;
  79. struct InternetBase * dev;
  80. int OpenIt = 0, 
  81.     CN1 = 0,
  82.     IOpenedIt = 0;
  83.  
  84. extern int DeviceSignal;
  85. extern struct Process *mytask;
  86.  
  87. printlist(l)
  88. struct List *l;
  89. {
  90.   printf("head %x tail %x tailpred %x\n", l->lh_Head, l->lh_Tail, 
  91.         l->lh_TailPred);
  92. }
  93. /*
  94.  *  Initialize and install the Amiga 'internet.device'.
  95.  */
  96. void
  97. DriverInit()
  98. {
  99.     char *foo[10];
  100.     int success;
  101.     static int WeWereHere;
  102.     int x;
  103.     tracedev("DriverInit");
  104.     x = WeWereHere; 
  105.     WeWereHere = 1;
  106.     if (x)
  107.       {
  108.         printf("you tried to add the driver twice!!!\n");
  109.         return;
  110.       }
  111.     foo[0] = (char *) &DSOpen;
  112.     foo[1] = (char *) &DSClose;
  113.     foo[2] = (char *) &DSExpunge;
  114.     foo[3] = (char *) NULL;
  115.     foo[4] = (char *) &DSBeginIO;
  116.     foo[5] = (char *) &DSAbortIO;
  117.         /* add any other custom routines here */
  118.     foo[6] = (char *) -1;
  119.  
  120.     InternetBase = (struct InternetBase *)
  121.         MakeLibrary(&foo[0], (char *) NULL, (char *) NULL,
  122.             (long) sizeof(struct InternetBase), (char *) NULL);
  123.  
  124.     if (InternetBase == (struct InternetBase *) 0) {
  125.         /* display alert? */
  126.         return;
  127.     }
  128.  
  129.     InitSemaphore(&(INLock));
  130.     ObtainSemaphore(&(INLock));
  131.     InitSemaphore(&(InternetBase->ib_lock));
  132.     InternetBase->ib_lock.ss_Link.ln_Pri = 0;
  133.     InternetBase->ib_lock.ss_Link.ln_Name = "internet.device lock";
  134.  
  135.     NewList(&InternetBase->ib_Units);
  136.     InternetBase->ib_Units.lh_Type = NT_UNKNOWN;
  137.  
  138.     InternetBase->lib.lib_Node.ln_Type = NT_DEVICE;
  139.     InternetBase->lib.lib_Node.ln_Pri = 0;
  140.     InternetBase->lib.lib_Node.ln_Name = "internet.device";
  141.     InternetBase->lib.lib_Flags = LIBF_CHANGED | LIBF_SUMUSED;
  142.     InternetBase->lib.lib_Version = IN_VERSION;
  143.     InternetBase->lib.lib_Revision = IN_REVISION;
  144.     InternetBase->lib.lib_IdString =
  145.              (APTR) "internet.device   23 May 1987\r\n";
  146.  
  147.     success = AddDevice(InternetBase);
  148.     Savea4();
  149.     OpenIt = 0;
  150.     IOpenedIt = 0;
  151.     nopens = 1;
  152.     CN1 = 5;
  153.     if (success != 0)
  154.           myoserr("driver open");
  155.     printf("driver added returned %d\n",success);
  156.  
  157. }
  158.  
  159. void
  160. DriverShutdown()
  161. {
  162.     long error;
  163.     extern long *RemoveDevice();
  164.  
  165.     if (!InternetBase)
  166.         return;
  167.  
  168.     if (error = RemDevice(InternetBase))
  169.         printf("Can't remove device: error %ld\n", error);
  170.  
  171. }
  172.  
  173. struct InternetBase *
  174. NetDevOpen(mdev, munit_spec, miob, mflags)
  175.     struct InternetBase *mdev;
  176.     struct IOINETReq *miob;
  177.     ULONG munit_spec, mflags;
  178. {
  179.  
  180.     iob = miob;
  181.     dev = mdev;
  182.     unit_spec = munit_spec;
  183.  
  184.     if (IOpenedIt == 1)
  185.       {
  186.         CN1++;
  187.         return NULL;
  188.       }
  189.     OpenIt = 1;
  190.     Permit();
  191.     while (IOpenedIt == 0);
  192.     Forbid();
  193.     IOpenedIt = 0;
  194.     return dev;
  195. }
  196. check_driver()
  197. {
  198.     register struct INET_Unit *unit;
  199.     register struct tcb *tcb;
  200.     if (OpenIt != 0)
  201.         {
  202.  
  203.     printf("open request!\n");
  204.     
  205.     switch (unit_spec) {
  206.         case INET_UNIT_TCP:
  207.         case INET_UNIT_UDP:
  208.             break;
  209.         default:
  210.             iob->io_Error = IOERR_OPENFAIL;
  211.             iob->io_Device = NULL;
  212.             iob->io_Unit = NULL;
  213.             OpenIt = 0;
  214.             IOpenedIt = 1;
  215.             goto doneopen;
  216.     }
  217.  
  218.     if ((unit = (struct INET_Unit *)
  219.             malloc(sizeof(struct INET_Unit))) == NULL) {
  220.         iob->io_Error = IOERR_OPENFAIL;
  221.         OpenIt = 0;
  222.         IOpenedIt = 1;
  223.         goto doneopen;
  224.     }
  225.     tracedev2("malloc ok %x\n", unit);
  226.     iob->io_Unit = unit;
  227.     iob->io_Device = (struct Device *)dev;
  228.     dev->lib.lib_OpenCnt++;
  229.  
  230.     unit->iu_Unit.ln_Type = NT_UNKNOWN;
  231.     unit->iu_Unit.ln_Pri = 0;
  232.  
  233.     NewList(&unit->iu_Input);
  234.     NewList(&unit->iu_Output);
  235. printf("newlist ok\n");
  236.     unit->iu_Input.lh_Type = NT_UNKNOWN;    /* gee, what do we really */
  237.     unit->iu_Output.lh_Type = NT_UNKNOWN;    /* call these... */
  238.     unit->iu_user = iob->io_Offset;        /* always returned in Offset */
  239.     unit->iu_Act_Input = NULL;
  240.     unit->iu_Act_Output = NULL;
  241.     iob->io_lsocket.address = ip_addr;
  242.     iob->io_lsocket.port = lport++;    
  243.     AddTail(&InternetBase->ib_Units, &unit->iu_Unit);
  244.     /* perform protocol specific open functions */
  245.     printf("addtail\n");
  246.  
  247.     switch (unit_spec) {
  248.     case INET_UNIT_TCP:
  249. /*        Forbid(); */
  250.         tcb = open_tcp(&(iob->io_lsocket), &(iob->io_fsocket),
  251.             (USHORT) iob->io_Offset, (USHORT) iob->io_TCP_Window,
  252.             indev_tcp_r_upcall, indev_tcp_t_upcall, indev_s_upcall,
  253.             iob->io_INET_TOS, (char *)unit);
  254.  
  255. /*        Permit();*/
  256.         if (tcb == NULL)
  257.             goto fail;
  258.         unit->iu_Unit.ln_Name = "TCP Connection";
  259.         unit->iu_type = INET_UNIT_TCP;
  260.         unit->iu_ccb = tcb;
  261. printf("cpopen is %d\n", tcb);
  262.         break;
  263.  
  264.     default:
  265.        fail:
  266.         iob->io_Error = IOERR_OPENFAIL;
  267.         dev->lib.lib_OpenCnt--;
  268.         Remove(unit);
  269.         free(unit);
  270.         OpenIt = 0;
  271.         IOpenedIt = 1;
  272.         goto doneopen;
  273.     }
  274.         tracedev2("dev is %d\n", dev);
  275.     OpenIt = 0;
  276.     IOpenedIt = 1;
  277.   }
  278. doneopen:
  279.   /* spin until that other guy is all done. We will not get through
  280.    * this spin until the other guy has done a Forbid() and
  281.    * then a Permit(), since the IopenedIt gets cleared 
  282.    * AFTER the Forbid(). Sorry i do not use semaphores but
  283.    * i do not have 1.2 autodocs so am not totally up on their
  284.    * use.
  285.    */
  286.   while (IOpenedIt);
  287. }
  288. CheckTcp()
  289. {
  290.   struct Node *head = InternetBase->ib_Units.lh_Head;
  291.  
  292.   struct INET_Unit *unit = (struct INET_Unit *) head;
  293.   struct tcb *tcb;
  294.   /* let the other guys in */
  295.   ReleaseSemaphore(&(INLock));
  296.   eihalt();
  297.   ObtainSemaphore(&(INLock));
  298.   tracedev("start checktcp\n");
  299.   tracedev4("heda %x Pred is %x Succ is %x\n", head,head->ln_Pred, head->ln_Succ);
  300.   for (;unit->iu_Unit.ln_Succ;unit = unit->iu_Unit.ln_Succ)
  301.     {
  302.       tracedev3("checktcp: %x Succ %d\n", unit, unit->iu_Unit.ln_Succ);
  303.       if (unit->iu_type != INET_UNIT_TCP)
  304.         {
  305.           tracedev("not a tcp\n");
  306.           continue;
  307.         }      
  308.       tcb = (struct tcb *) unit->iu_ccb;
  309.       if (tcb == NULL)
  310.         {
  311.           tracedev("NULL tcb in unit\n");  
  312.           continue;
  313.         }
  314.       if (tcb->state == ESTABLISHED)
  315.         {
  316.           tracedev("unit state is established!\n");
  317. /*          continue;*/
  318.         }
  319.      tracedev("do the upcall\n");
  320.      do_tupcall(tcb, 512); /* for now- it wil do the right thing */
  321.      if (tcb->rcvcnt > 0)
  322.        do_rupcall(tcb, tcb->rcvcnt);
  323.   }
  324.   tracedev("done checktcp\n");
  325. /*  ReleaseSemaphore(&(INLock));*/
  326. }
  327. void DevClose(dev, iob)
  328.     struct InternetBase *dev;
  329.     struct IOINETReq *iob;
  330. {
  331.     register struct INET_Unit *unit;
  332.         struct tcb *tcb;
  333.  
  334.         unit = iob->io_Unit;
  335.         tcb = unit->iu_ccb;
  336.     del_tcp(tcb);
  337.     Remove(unit);
  338.     free(unit);
  339.     iob->io_Unit = NULL;
  340.  
  341.     iob->io_Device = (struct Device *)dev;
  342.     dev->lib.lib_OpenCnt--;
  343.  
  344.     /* remove iu_Unit from ib_Units list */
  345.     /* decrement library use count */
  346.     /* free unit structure */
  347.     /* delete TCP/UDP connection del_tcp()/del_udp() */
  348. }
  349.  
  350. long DevExpunge(dev)
  351.     struct InternetBase *dev;
  352. {
  353.     register char *m;
  354.     register long len;
  355.  
  356.  
  357.     if (InternetBase->lib.lib_OpenCnt) {
  358.         InternetBase->lib.lib_Flags |= LIBF_DELEXP;
  359.         return 0;
  360.     }
  361.     Remove(InternetBase);    /* remove from library list */
  362.     len = InternetBase->lib.lib_NegSize + InternetBase->lib.lib_PosSize;
  363.     m = (char *) ((ULONG)InternetBase - InternetBase->lib.lib_NegSize);
  364.     FreeMem(m, len);
  365.     return 0;
  366. }
  367.  
  368. #define    C_IMMED        (1<<0)
  369. #define    C_READ        (1<<1)
  370. #define    C_WRITE        (1<<2)
  371. void cmd_Invalid(), cmd_Reset(), cmd_Read(), cmd_Write(), cmd_Update(),
  372.     cmd_Clear(), cmd_Stop(), cmd_Start(), cmd_Flush(), PerformIO();
  373.  
  374. struct Commands {
  375.     void    (*cmd_func)();
  376.     int    cmd_flags;
  377. } commands [] = {
  378.     { cmd_Invalid,     C_IMMED        },    /* invalid    */
  379.     { cmd_Reset,    C_IMMED        },    /* CMD_RESET    */
  380.     { cmd_Read,    C_READ        },    /* CMD_READ    */
  381.     { cmd_Write,    C_WRITE        },    /* CMD_WRITE    */
  382.     { cmd_Update,    C_WRITE     },    /* CMD_UPDATE    */
  383.     { cmd_Clear,    C_IMMED        },    /* CMD_CLEAR    */
  384.     { cmd_Stop,    C_IMMED        },    /* CMD_STOP    */
  385.     { cmd_Start,    C_IMMED        },    /* CMD_START    */
  386.     { cmd_Flush,    C_IMMED        },    /* CMD_FLUSH    */
  387. };
  388.  
  389. /*  define last valid command */
  390. #define    MAX_IO_COMMAND    CMD_FLUSH
  391.  
  392.  
  393. /* BeginIO is called to begin processing of the I/O request */
  394.  
  395. void DevBeginIO(iob, dev)
  396.     struct IOINETReq *iob;
  397.     struct InternetBase *dev;
  398. {
  399.     register struct Commands *cmd;
  400.     register struct INET_Unit *unit = iob->io_Unit;
  401.     ObtainSemaphore(&(INLock));
  402.     if (iob->io_Command > MAX_IO_COMMAND) {
  403.         cmd_Invalid(iob, iob->io_Unit);
  404.         goto done;
  405.     }
  406.     tracedev("io. ObtainSme\n");
  407.  
  408.     tracedev("got it\n");
  409.     cmd = &commands[iob->io_Command];
  410.     tracedev2("cmd is %d\n",iob->io_Command);
  411.     tracedev2("flags %d\n", iob->io_Flags);
  412.     if ((cmd->cmd_flags & C_IMMED) == 0) {
  413.  
  414.         /*
  415.          *  Code for commands which can queue
  416.          */
  417.  
  418.         if ((cmd->cmd_flags & C_READ)/* && (unit->iu_Act_Input)*/) {
  419.             AddTail(&unit->iu_Input, iob);
  420.             iob->io_Flags &= ~IOF_QUICK;
  421.             iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  422.             tracedev3("added %d to read queue of unit %d\n", iob, unit);
  423.             goto done;
  424.         }
  425.  
  426.         if ((cmd->cmd_flags & C_WRITE)/* && (unit->iu_Act_Output)*/) {
  427.             AddTail(&unit->iu_Output, iob);
  428.             iob->io_Flags &= ~IOF_QUICK;
  429.             iob->io_Message.mn_Node.ln_Type = NT_MESSAGE;
  430.             tracedev3("added %d to write queue of unit %d\n", iob, unit);
  431.             goto done;
  432.         }
  433.     }
  434.     PerformIO(iob, unit);
  435. done:     tracedev4("flags QUI %x ~QUI %x  %d\n", IOF_QUICK, ~IOF_QUICK,
  436.             iob->io_Flags);
  437.   Signal(mytask, DeviceSignal);
  438.   ReleaseSemaphore(&(INLock));
  439. }
  440.  
  441. void DevAbortIO(iob, dev)
  442.     struct IOINETReq *iob;
  443.     struct InternetBase *dev;
  444. {
  445.     printf("DevAbortIo\n");
  446. }
  447.  
  448. void
  449. PerformIO(iob, unit)
  450.     struct IOINETReq *iob;
  451.     struct INET_Unit *unit;
  452. {
  453.     iob->io_Error = 0;
  454.     iob->io_Actual = 0;
  455.     (*commands[iob->io_Command].cmd_func)(iob, unit);
  456. }
  457.  
  458. void
  459. TermIO(iob, unit)
  460.     struct IOINETReq *iob;
  461.     struct INET_Unit *unit;
  462. {
  463.     struct tcb *tcb;
  464.         tcb = (struct tcb *) unit->iu_ccb;
  465.     iob->io_OldState = iob->io_State;
  466.     iob->io_State = tcb->state;
  467.     if ((iob->io_Flags & IOF_QUICK) == 0)
  468.         /* not quick I/O */
  469.         ReplyMsg(&iob->io_Message);
  470. }
  471.  
  472. void
  473. cmd_Invalid(iob, unit)
  474.     struct IOINETReq *iob;
  475.     struct INET_Unit *unit;
  476. {
  477.     iob->io_Error = IOERR_NOCMD;
  478.     TermIO(iob, unit);
  479. }
  480.  
  481. void
  482. cmd_Reset(iob, unit)
  483.     struct IOINETReq *iob;
  484.     struct INET_Unit *unit;
  485. {
  486.     iob->io_Error = IOERR_NOCMD;
  487.     TermIO(iob, unit);
  488. }
  489.  
  490. void
  491. cmd_Read(iob, unit)
  492.     struct IOINETReq *iob;
  493.     struct INET_Unit *unit;
  494. {
  495.     iob->io_Error = IOERR_NOCMD;
  496.     TermIO(iob, unit);
  497. }
  498.  
  499. void
  500. cmd_Write(iob, unit)
  501.     struct IOINETReq *iob;
  502.     struct INET_Unit *unit;
  503. {
  504.     iob->io_Error = IOERR_NOCMD;
  505.     TermIO(iob, unit);
  506. }
  507.  
  508. void
  509. cmd_Update(iob, unit)
  510.     struct IOINETReq *iob;
  511.     struct INET_Unit *unit;
  512. {
  513.     iob->io_Error = IOERR_NOCMD;
  514.     TermIO(iob, unit);
  515. }
  516.  
  517. void
  518. cmd_Clear(iob, unit)
  519.     struct IOINETReq *iob;
  520.     struct INET_Unit *unit;
  521. {
  522.     iob->io_Error = IOERR_NOCMD;
  523.     TermIO(iob, unit);
  524. }
  525.  
  526.  
  527. void
  528. cmd_Stop(iob, unit)
  529.     struct IOINETReq *iob;
  530.     struct INET_Unit *unit;
  531. {
  532.     iob->io_Error = IOERR_NOCMD;
  533.     TermIO(iob, unit);
  534. }
  535.  
  536.  
  537. void
  538. cmd_Start(iob, unit)
  539.     struct IOINETReq *iob;
  540.     struct INET_Unit *unit;
  541. {
  542.     iob->io_Error = IOERR_NOCMD;
  543.     TermIO(iob, unit);
  544. }
  545.  
  546.  
  547. void
  548. cmd_Flush(iob, unit)
  549.     struct IOINETReq *iob;
  550.     struct INET_Unit *unit;
  551. {
  552.     iob->io_Error = IOERR_NOCMD;
  553.     TermIO(iob, unit);
  554. }
  555.  
  556.  
  557. /* TCP receiver upcall routine.  Called with TCB pointer and number of bytes
  558.    available */
  559.  
  560.  
  561. do_rupcall(tcb, cnt)
  562.     struct tcb *tcb;
  563.     int16 cnt;
  564. {
  565.     struct mbuf *bp;
  566.     register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
  567.     int amount, recamount;
  568.     struct IOINETReq *iob;
  569. /*    ObtainSemaphore(&(INLock));*/
  570.     if (ListEmpty(&(unit->iu_Input)))
  571.       goto done;
  572.     iob = unit->iu_Act_Input = unit->iu_Input.lh_Head;
  573.     tracedev4("dev rupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
  574.     if (iob != NULL)
  575.       {
  576.         Remove(iob);
  577.             amount = min(cnt, iob->io_Length);
  578.         tracedev3("call recv_tcp %d bytes avail %d\n", amount, cnt);
  579.         recamount = recv_tcp(tcb, &bp, amount);
  580.         iob->io_Actual = dqdata(bp, iob->io_Data, recamount);
  581.         tracedev2("recv_tcp after got %d bytes\n", iob->io_Actual);
  582.         TermIO(iob, unit);
  583. /*        ReplyMsg(&(iob->io_Message));*/
  584.       }
  585. done:    
  586. /*  ReleaseSemaphore(&(INLock));        */
  587. }
  588. /* TCP receiver upcall routine.  Called with TCB pointer and number of bytes
  589.    available */
  590.  
  591. void
  592. indev_tcp_r_upcall(tcb, cnt)
  593.     struct tcb *tcb;
  594.     int16 cnt;
  595. {
  596. /*    ObtainSemaphore(&(INLock));*/
  597.     do_rupcall(tcb, 512);
  598. /*  ReleaseSemaphore(&(INLock));        */
  599. }
  600.  
  601. /* TCP transmitter upcall routine.  Called with TCB pointer and number of bytes
  602.    free in send window */
  603.  
  604.  
  605. do_tupcall(tcb, avail)
  606.     struct tcb *tcb;
  607.     int16 avail;
  608. {
  609.     struct mbuf *bp, *qdata();
  610.     register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
  611.     int amount;
  612.     struct IOINETReq *iob;
  613.  
  614.     if (ListEmpty(&(unit->iu_Output)))
  615.       goto done;
  616.     tracedev("non-empty Output\n");
  617.     iob = unit->iu_Act_Output = unit->iu_Output.lh_Head;
  618.     tracedev4("dev tupcall iob %d unit %d tcb%d\n",iob, unit, tcb);
  619.     if (iob != NULL)
  620.       {
  621.         Remove(iob);
  622.  
  623.             amount = min(avail, iob->io_Length);
  624.         tracedev3("t_upcall- send_tcp for addr %x %d bytes\n",iob->io_Data,
  625.             amount);
  626.         bp = qdata(iob->io_Data, amount);
  627.         iob->io_Actual = send_tcp(tcb, bp);
  628.         tracedev2("send_tcp after got %d bytes\n", iob->io_Actual);
  629.         TermIO(iob, unit);
  630. /*        ReplyMsg(&(iob->io_Message));*/
  631.         unit->iu_Act_Output = NULL;
  632.       }
  633. done:
  634.  
  635.  
  636. }
  637. void
  638. indev_tcp_t_upcall(tcb, avail)
  639.     struct tcb *tcb;
  640.     int16 avail;
  641. {
  642. /*    ObtainSemaphore(&(INLock));*/
  643.     do_tupcall(tcb, avail);
  644. /*  ReleaseSemaphore(&(INLock));        */
  645.  
  646. }
  647.  
  648. void
  649. indev_s_upcall(tcb, old, new)
  650.     struct tcb *tcb;
  651.     char old, new;
  652. {
  653.     register struct INET_Unit *unit = (struct INET_Unit *) tcb->user;
  654.     char notify = 0;
  655.     extern char *tcpstates[];
  656.     extern char *reasons[];
  657.     extern char *unreach[];
  658.     extern char *exceed[];
  659.  
  660.     /* Can't add a check for unknown connection here, it would loop
  661.      * on a close upcall! We're just careful later on.
  662.      */
  663.  
  664.     if(unit != NULL)
  665.         notify = 1;
  666.  
  667.     switch(new){
  668.     case CLOSE_WAIT:
  669.         if(notify)
  670.             printf("%s\r\n",tcpstates[new]);
  671.         close_tcp(tcb);
  672.         break;
  673.     case CLOSED:    /* court adjourned */
  674.         if(notify){
  675.             printf("%s (%s",tcpstates[new],reasons[tcb->reason]);
  676.             if(tcb->reason == NETWORK){
  677.                 switch(tcb->type){
  678.                 case DEST_UNREACH:
  679.                     printf(": %s unreachable",unreach[tcb->code]);
  680.                     break;
  681.                 case TIME_EXCEED:
  682.                     printf(": %s time exceeded",exceed[tcb->code]);
  683.                     break;
  684.                 }
  685.             }
  686.             printf(")\r\n");
  687.         }
  688.         del_tcp(tcb);
  689.         break;
  690.     default:
  691.         if(notify)
  692.             printf("%s\r\n",tcpstates[new]);
  693.         break;
  694.     }
  695.     fflush(stdout);
  696.  
  697. }
  698. #endif
  699.